/*
 * This PAC agent is the intermediate level agent that controls story creation and hosting.
 * When the authorStory() method is called, this agent creates a new listener (to accept
 * connection requests and redirect them to their own thread) and transfers user control to a
 * newly created JoinStoryAgent. Once the story has been created, the original author uses
 * the same agent as any contributors who join later (though they would of course be a separate
 * instance of it).
 */

import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.JOptionPane;
public class CreateStoryAgent {

	//Abstraction component to store the current story model, including the authors and current author.
	String storyTitle;
	ArrayList<String> story;
	ArrayList<String> authors;
	String currentAuthor;
	ArrayList<NetCommunicationWrapper> authorConns;
	Scanner in;

	CreateStoryAgent()
	{
		storyTitle = null;
		story = new ArrayList<String>();
		authors = new ArrayList<String>();
		currentAuthor = null;
		authorConns = new ArrayList<NetCommunicationWrapper>();
		in = new Scanner(System.in);
	}

	// This is part 1 of 3 of the control aspect of the CreateStoryAgent. This sets the story title variable,
	// creates a listener thread to handle incomming connections, then starts the original
	// author in their own JoinStoryAgent thread, which is joined by giving it its own CSAClientCommunication thread.
	// This thread then waits for the user to exit the story, by closing the JoinStoryAgent thread.
	public void authorStory()
	{
		storyTitle = getStoryTitle();

		CSAListener cSAL = new CSAListener();
		Thread cSALT = new Thread(cSAL);
		cSALT.start();

		NetCommunicationWrapper conn = new NetCommunicationWrapper();
		conn.connect(IPv4Wrapper.getLocalHost());
		JoinStoryAgent jSA = new JoinStoryAgent(conn);
		Thread jSAT = new Thread(jSA);
		jSAT.start();

		while(true)
		{
			if(jSAT.getState() == Thread.State.TERMINATED) {
				if(shouldTerminateServer()) {
					return;
				}
			}
		}
	}

	// Presentation component part 1 of 2.
	// Prompts the user for the story title, then returns it.
	private String getStoryTitle()
	{
		String storyTitle = JOptionPane.showInputDialog(null,"Enter the title of the story:","Stories Title?", JOptionPane.INFORMATION_MESSAGE);
		return storyTitle;
	}

	// Presentation component part 2 of 2.
	// Asks the user if, now that they've left the story, the story server should terminate.
	private boolean shouldTerminateServer()
	{
		Object[] options = {"No, thanks!", "Yes, Please!"};
		int n = JOptionPane.showOptionDialog(null,"Should the story be terminated?",
				"Exit?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
				null, options, options[1]);
		if(n == 1) {
			return true;
		}
		else {
			return false;
		}
	}

	// Part 2 of 3 of the CreateStoryAgent control. This interfaces with JoinStoryAgents trying to connect using the NetCommunicationWrapper.
	// This is to run in its own thread. Once an incoming connection is received, it is passed off to its own CSAClientCommunicator
	// thread with its own connection.
	private class CSAListener implements Runnable{
		@Override
		public void run() {
			while(true)
			{
				NetCommunicationWrapper conn = new NetCommunicationWrapper();
				if(conn.listen())
				{
					CSAClientCommunicator cSACC = new CSAClientCommunicator(conn);
					Thread cSACCT = new Thread(cSACC);
					cSACCT.start();
				}
			}
		}
	}

	// Part 3 of 3 of the CreateStoryAgent control. This interfaces with JoinStoryAgents using the NetCommunicationWrapper.
	// This is to run in its own thread. This is the server side network interface, sending/receiving commands and processing
	// data requests.
	private class CSAClientCommunicator implements Runnable{
		NetCommunicationWrapper conn;	//Server side connection to a JoinStoryAgent.

		CSAClientCommunicator(NetCommunicationWrapper conn)
		{
			this.conn = conn;
		}

		/*
		 * Command List:
		 * 1 - Send Story Title
		 * 2 - Send Story Contents
		 * 3 - Send Current Writer
		 * 4 - Sending Addition
		 * 5 - Leaving Story
		 * 6 - Send author.
		 * # - Get story title and close connection.
		 */
		@Override
		public void run() {
			conn.send("6");	//Request author name.
			String thisAuthor;
			thisAuthor = conn.receiveString();

			// The # symbol is the command to send a story title and terminate the thread.
			// The connection was not from an actual author, but was used to populate a story list.
			if(thisAuthor.equals("#"))
			{
				conn.send(storyTitle);
				try {
					Thread.currentThread().sleep(1000);
				} catch (InterruptedException e) {
				}
				return;
			}

			// Add this new author to the list. If there is no currentAuthor, this is the new one.
			authors.add(thisAuthor);
			if(currentAuthor == null) {
				currentAuthor = thisAuthor;
			}

			while(true)	//Check for commands and process them.
			{
				//Populate the currentAuthorIndex field, to be used to access the name of the current author.
				int currentAuthorIndex = -1;
				for(int i = 0; i < authors.size(); i++)
				{
					if(authors.get(i).equals(currentAuthor)) {
						currentAuthorIndex = i;
					}

				}

				int command = Integer.parseInt(conn.receiveString());
				if(command == 1)	//Get Story Title
				{
					conn.send(storyTitle);
				}
				else if(command == 2)	//Get Story Contents
				{
					conn.send("" + story.size());
					for(int i = 0; i < story.size(); i++)
					{
						conn.send(story.get(i));
					}
				}
				else if(command == 3)	//Get current writer
				{
					conn.send(authors.get(currentAuthorIndex));
				}

				else if(command == 4)	//Sending Addition
				{
					if(currentAuthor == thisAuthor)
					{
						story.add(conn.receiveString());
						//If the current author is the last on the list, reset the author to the first one (beginning of the list).
						if(currentAuthorIndex == authors.size() -1)
						{
							currentAuthor = authors.get(0);
						} else {
							currentAuthor = authors.get(currentAuthorIndex+1);
						}
					}
				}
				else if(command == 5)	//Leaving. Remove this author from the authors ArrayList
				{
					int thisAuthorIndex = -1;
					for(int i = 0; i < authors.size(); i++)
					{
						if(authors.get(i).equals(thisAuthor)) {
							thisAuthorIndex = i;
						}

					}
					authors.remove(thisAuthorIndex);
				}
			}
		}
	}
}
